#include <stdio.h>      // 标准输入输出，用于fprintf
#include <dlfcn.h>      // 动态链接库函数，用于dlsym
#include <fcntl.h>      // 文件控制选项，定义O_CREAT等标志
#include <stdarg.h>     // 可变参数处理，用于va_list等
#include <errno.h>      // 错误码定义，用于设置errno
#include <sys/types.h>  // mode_t类型定义

// 如果RTLD_NEXT未定义，手动定义它
#ifndef RTLD_NEXT
#define RTLD_NEXT ((void *) -1l)
#endif

// 声明原始open函数的函数指针
static int (*orig_open)(const char *, int, ...) = NULL;

// 构造函数：在动态链接库被加载时自动调用 GCC扩展
// 这个函数会在main函数执行之前被调用
__attribute__((constructor))
static void init(void) {
    // 使用dlsym获取原始open函数的地址
    // RTLD_NEXT表示查找下一个包含"open"符号的库
    orig_open = dlsym(RTLD_NEXT, "open");
    
    // 检查是否成功获取到原始函数
    if (!orig_open) {
        fprintf(stderr, "[审计] 错误：无法获取原始open函数: %s\n", dlerror());
    }
}

// 我们的hook版本的open函数
// 函数签名必须与原始open函数完全一致
// ... 表示可变参数，用于处理可选的mode参数
int open(const char *filename, int flags, ...) {
    // 声明mode变量，默认为0
    // mode_t是文件权限类型，在创建文件时需要指定
    mode_t mode = 0;
    
    // 通过varargs获取mode参数
    if (flags & O_CREAT) {
        va_list args;
        
        va_start(args, flags);
        
        mode = va_arg(args, mode_t);
        
        va_end(args);
    }
    
    if (NULL == orig_open) {
        fprintf(stderr, "[审计] 错误：无法获取原始open函数\n");
        return -1;
    }

    // 调用原始的open函数
    int fd = orig_open(filename, flags, mode);
    
    // 记录审计日志
    fprintf(stderr, "[审计] 打开文件：%s, 文件描述符：%d\n", filename, fd);
    
    return fd;
}
